﻿// CustomAuthorizationAttribute.cs
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;
using System.Reflection;

namespace System.ComponentModel.DataAnnotations {

    /// <summary>
    /// An authorization attribute that invokes the specified authorization method when asked to
    /// authorize a user for a particular operation.
    /// </summary>
    public sealed class CustomAuthorizationAttribute : AuthorizationAttribute {

        private Type _type;
        private string _methodName;
        private MethodInfo _method;

        /// <summary>
        /// Initializes an instance of a CustomAuthorizationAttribute.
        /// </summary>
        /// <param name="type">The type containing the authorization method implementation.</param>
        /// <param name="methodName">The name of the static method to invoke to perform authorization.</param>
        public CustomAuthorizationAttribute(Type type, string methodName) {
            _type = type;
            _methodName = methodName;
        }

        /// <internalonly />
        protected override AuthorizationResult IsAuthorized(IPrincipal principal, AuthorizationContext authorizationContext) {
            if (_method == null) {
                if (_type == null) {
                    throw new InvalidOperationException("A valid type must be specified for use with [CustomAuthorization].");
                }
                if (String.IsNullOrEmpty(_methodName)) {
                    throw new InvalidOperationException("A valid method on the type '" + _type.FullName + "' must be specified for use with [CustomAuthorization].");
                }

                _method = _type.GetMethod(_methodName, BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static);
                if (_method == null) {
                    throw new InvalidOperationException("The authorization method named '" + _methodName + "' on the type '" + _type.FullName + "' for use with [CustomAuthorization] was not found.");
                }
            }

            return (AuthorizationResult)_method.Invoke(null, new object[] { principal, authorizationContext });
        }
    }
}
